use std::sync::Arc;

use futures::stream::{SplitSink, SplitStream};
use futures::StreamExt;
use tokio::net::TcpStream;
use tokio::sync::Mutex;
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
use tokio_tungstenite::tungstenite::{connect, Message};
use crate::auth::get_gateway;
use crate::model::WebSocketMessage;

mod heart_beat;
mod auth;
mod message;

pub async fn start() {
    loop {
        let gateway_url = get_gateway().await;
        let (ws_stream, _) = connect_async(gateway_url).await.expect("连接失败！");
        let (ws_write, ws_read) = ws_stream.split();
        let writer = Arc::new(Mutex::new(ws_write));
        let read = Arc::new(Mutex::new(ws_read));
        let listen = tokio::spawn(listen(read, writer));
        match listen.await {
            Ok(_) => {}
            Err(_) => {}
        };
    }
}

pub async fn listen(arc_read: Arc<Mutex<SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>>>, arc_writer: Arc<Mutex<SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, Message>>>) {
    let mut read = arc_read.lock().await;
    let session_id = Arc::new(Mutex::new(String::from("")));
    loop {
        let read_msg =  read.next().await;
        match read_msg {
            Some(Ok(Message::Text(msg_string))) => {
                let json = serde_json::from_str::<WebSocketMessage>(msg_string.as_str()).ok();
                if let Some(message) = json {
                    if let Some(d) = message.d.clone() {
                        let session = Arc::clone(&session_id);
                        let mut id = session.lock().await;
                        *id = String::from(d.session_id.unwrap_or("".to_string()));
                    }
                    if message.op.eq(&Some(10)) {
                        auth::handle(message, &arc_writer).await;
                    }else if message.op.eq(&Some(0)){
                        let id = Arc::clone(&session_id);
                        let write = Arc::clone(&arc_writer);
                        message::handle(id, msg_string.to_string(), write).await;
                    }
                }
            }
            Some(Ok(Message::Close(close))) => {
                println!("{:?}", close);
                break;
            }
            Some(Err(error)) => {
                println!("{:?}", error);
            }
            None => {}
            err => {
                println!("{:?}", err);
                break;
            }
        }
    }
}